
package com.goldsand.collaboration.handoff.server.connection;

import android.util.Log;

import com.goldsand.collaboration.handoff.common.connection.NewMessageListener;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServerConnectionThread extends Thread {
    protected volatile boolean mStopRuning = false;
    protected volatile boolean mStopConnection = false;
    private Socket mConnectionSocket = null;
    private ObjectInputStream mObjectInputStream = null;
    private ObjectOutputStream mObjectOutputStream = null;
    private final String TAG;
    private boolean mConnected = false;
    private NewMessageListener mNewMessageListener = null;

    public SocketServerConnectionThread(String name) {
        super(name);
        TAG = name;
    }

    /**
     * Invoke when thread start. Override to change the running status Or other
     * init things. like create ServerSocket.
     */
    protected void initRunningArgument() {
        mStopRuning = false;
        mStopConnection = false;
    }

    /*
     * Invoke when thread done. for Server Thread need override to release the
     * ServerSocket.
     */
    protected void releaseServerSocket() {
        if (mObjectInputStream != null) {
            try {
                mObjectInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mObjectInputStream = null;
        }
        if (mObjectOutputStream != null) {
            try {
                mObjectOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mObjectOutputStream = null;
        }
        if (mConnectionSocket != null) {
            try {
                mConnectionSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mConnectionSocket = null;
        }
    }

    /**
     * Get the connection status
     * 
     * @return if connected true else false
     */
    public boolean isConnected() {
        return mConnected;
    }

    /**
     * Can use this function to send data to Client
     * 
     * @param o
     * @throws Exception
     */
    public void sendDataToClient(final Object o) throws Exception {
        new Thread(Thread.currentThread().getName() + "_send_data_thread") {
            @Override
            public void run() {
                try {
                    Log.v(TAG, "Data to send " + (String) o + (mConnectionSocket != null)
                            + (mObjectOutputStream == null));
                    if (mConnected) {
                        if (mConnectionSocket != null && mObjectOutputStream == null) {
                            OutputStream outputStream = mConnectionSocket.getOutputStream();
                            mObjectOutputStream = new ObjectOutputStream(outputStream);
                        }
                        mObjectOutputStream.writeObject(o);
                        mObjectOutputStream.flush();
                    } else {
                        Log.e(TAG, "Socket do not connected");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    /**
     * Just stop the connection, but don't exit the thread.
     */
    public void stopConnection() {
        mStopConnection = true;
    }

    /**
     * disconnected the connection, and exit the thread.
     */
    public void stopRuning() {
        mStopConnection = true;
        mStopRuning = true;
    }

    /**
     * Set the message receive listener
     * 
     * @param listener
     */
    public void setNewMessageReceiveListener(NewMessageListener listener) {
        mNewMessageListener = listener;
    }

    private Object getDataFromClient() throws Exception {
        Log.d(TAG, "start get message");
        if (mConnectionSocket != null && mObjectInputStream == null) {
            InputStream inputStream = mConnectionSocket.getInputStream();
            mObjectInputStream = new ObjectInputStream(inputStream);
        }
        return mObjectInputStream.readObject();
    }

    public void run() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(10081);
            while (!mStopRuning) {
                // We just need one connection.So if connected , we will not
                // continue to accept new socket
                mConnectionSocket = serverSocket.accept();
                mConnected = true;
                if (mConnectionSocket == null) {
                    Log.e(TAG, " null socket");
                    return;
                }
                sendDataToClient("JustForTest");
                while (!mStopConnection) {
                    String in = (String) getDataFromClient();
                    Log.v(TAG, "get message:" + in);
                    if (mNewMessageListener != null) {
                        mNewMessageListener.onNewMessageReceived(getName(), in);
                    }
                    // TODO stop
                    if ("stop".equals(in)) {
                        mStopConnection = true;
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            Log.e(TAG, "bey bey!");
            releaseServerSocket();
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
